<?php
/**
 * 操作数据前行为验证
 * 2019.8.3
 */
namespace app\manage\behavior;


use app\manage\model\Token;
use think\Db;


class Check
{
	public function moduleInit()
	{
		#不验证sign的方法,
        $excludeSign = [
//            'applet/member/login',#登录
//            'applet/test/testToken', #测试签名的接口
        ];
        //验证签名
        if( !in_array($action = $this->getAction(), $excludeSign) )
        {
//             $this->checkSign($input); //验证签名
        }
        //不需要验证登陆token
        $exclude = [
            'manage/login/login',#登录
            'share/upload/upToken', #测试签名的接口
            'manage/goods/goodsSubmit', #测试签名的接口
        ];

        if( !in_array($action = $this->getAction(), $exclude) ){
           //没有在$exclude数组里面的都需要验证登陆,token是否存在
           $TokenCheck = new Token();
           //$TokenCheck->checkToken( get_header_param("token") );
        }

        //$user_id=get_header_id('token');
        //验证权限
        //$res=$this->cmf_auth_check($user_id);
        //dump($res);
        //if(!$res){
           // returnJson( 403, "您没有访问权限!");
        //}
	}



    //解析操作形成
    private function getAction()
    {
        return strtolower(request()->module())."/".strtolower(request()->controller())."/".strtolower(request()->action());
    }
    //验证签名,确保接口数据安全和避免重放
    private function checkSign( $input )
    {
        $sign      = trim(get_header_param('sign'));
        $timestamp = trim(get_header_param('timestamp'));
        if(empty($sign))
        {
            returnJson(-1004,'sign不能为空');
        }
        if(empty($timestamp))
        {
            returnJson(-1005,'timestamp不能为空');
        }
        //请求仅在30s有效
        if( abs($timestamp - time()) >=30000 )
        {
            returnJson(-1006,  "当前url请求超时");
        }
        $from_sign = $sign;
        $input['timestamp'] = get_header_param('timestamp');
        $sign = $this->getSign( $input );
        if( $from_sign !== $sign ){
            returnJson(-1007,  "签名验证失败");
        }
    }
    /*
     *  生成sign签名  yuYan123456!@#
     */
    private function getSign( $data )
    {
        foreach ($data as $k => $v) {
            if(null === $v && $v !== 0 ){
                unset($data[$k]);
            }
        }
        foreach ($data as $k => $v)
        {
            $Parameters[$k] = $v;
        }
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, TRUE);
        $String = $String."&key=".config('api_sign_key');
        $result_ = strtoupper( md5( $String ) );
        return $result_;
    }
    //将数组转成uri字符串
    private function formatBizQueryParaMap($paraMap, $urLenCode)
    {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v)
        {
            if($urLenCode)
            {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = "";
        if (strlen($buff) > 0)
        {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }

    /**
     * 检查权限
     * @param $userId   int        要检查权限的用户 ID
     * @param $name     string|array  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param $relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
     * @return boolean            通过验证返回true;失败返回false
     */
    function cmf_auth_check($userId, $name = null, $relation = 'or')
    {
        if (empty($userId)) {
            return false;
        }

        if ($userId == 1) {
            return true;
        }

        if (empty($name)) {
            $request    = request();
            $module     = $request->module();
            $controller = $request->controller();
            $action     = $request->action();
            $name       = strtolower($module . "/" . $controller . "/" . $action);
        }
        //dump($name);
        return $this->check($userId, $name, $relation);
    }

    /**
     * 检查权限
     * @param $name     string|array  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param $uid      int           认证用户的id
     * @param $relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
     * @return boolean           通过验证返回true;失败返回false
     */
    public function check($uid, $name, $relation = 'or')
    {

        if (empty($uid)) {
            return false;
        }
        if ($uid == 1) {
            return true;
        }

        if (is_string($name)) {
            $name = strtolower($name);
            if (strpos($name, ',') !== false) {
                $name = explode(',', $name);
            } else {

                $findAuthRuleCount = Db::name('auth_rule')->where([
                    'name' => $name
                ])->count();

                if ($findAuthRuleCount == 0) {//没有规则时,不验证!
                    return true;
                }

                $name = [$name];
            }
        }
        //dump('11111111111');
        //dump($name);

        $list   = []; //保存验证通过的规则名
        $groups = Db::name('RoleUser')
            ->alias("a")
            ->join('__ROLE__ r', 'a.role_id = r.r_id')
            ->where(["a.user_id" => $uid, "r.status" => 1])
            ->column("role_id");

        if (in_array(1, $groups)) {
            return true;
        }

        //dump('2222222');
        if (empty($groups)) {
            return false;
        }
        //dump('3333333');
        $rules = Db::name('AuthAccess')
            ->alias("a")
            ->join('__AUTH_RULE__ b ', ' a.rule_name = b.name')
            ->where('a.role_id', 'in', $groups)
            ->where('b.name', 'in', $name)
            ->select();
        foreach ($rules as $rule) {
            if (!empty($rule['condition'])) { //根据condition进行验证
                //$user = $this->getUserInfo($uid);//获取用户信息,一维数组

                $command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);
                //dump($command);//debug
                @(eval('$condition=(' . $command . ');'));
                if ($condition) {
                    $list[] = strtolower($rule['name']);
                }
            } else {
                $list[] = strtolower($rule['name']);
            }
        }
        //dump('444444');
        if ($relation == 'or' and !empty($list)) {
            return true;
        }
        //dump('5555555');
        $diff = array_diff($name, $list);
        if ($relation == 'and' and empty($diff)) {
            return true;
        }
        return false;
    }


}